#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "esp_log.h"
#include "driver/gpio.h"

// 宏定义GPIO输入的引脚号
#define GPIO_INPUT_BOOT     9
#define GPIO_INPUT_PIN_SEL  (1ULL<<GPIO_INPUT_BOOT)
#define ESP_INTR_FLAG_DEFAULT 0

// 全局常量, 字符串, 用于日志打印的标签
const static char* TAG = "semaphore";

// 全局变量, 信号量, 中断到任务的信息同步
static SemaphoreHandle_t isr_semphr = NULL;

// 全局变量, 信号量, 任务到任务的信息同步
static QueueHandle_t task_semphr = NULL;

// 中断回调函数
static void IRAM_ATTR gpio_isr_handler(void* arg)
{
    uint32_t gpio_num = (uint32_t) arg;
    if(gpio_num==GPIO_INPUT_BOOT){
        xSemaphoreGiveFromISR(isr_semphr, NULL);
    }
}

// button初始化
void button_init(void)
{
    gpio_config_t io_conf = {};
    //设置IO引脚：宏定义中修改
    io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL;
    //设置IO方向：输入
    io_conf.mode = GPIO_MODE_INPUT;
    //设置IO上拉：使能
    io_conf.pull_up_en = 1;
    //设置IO中断类型：上升沿中断和下降沿
    io_conf.intr_type = GPIO_INTR_POSEDGE;
    //配置GPIO
    gpio_config(&io_conf);

    //安装GPIO中断服务
    gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
    //添加GPIO_INPUT_BOOT 中断回调函数
    gpio_isr_handler_add(GPIO_INPUT_BOOT, gpio_isr_handler, (void*) GPIO_INPUT_BOOT);
}

// 核心任务
static void coreTask(void* arg)
{  
    while(true) {
        // 堵塞等待获取信号量isr_semphr
        if(xSemaphoreTake(isr_semphr, portMAX_DELAY)) {
            // 获取成功
            ESP_LOGI(TAG, "take semaphore, core processing for 1 second");
            // 延时1s
            vTaskDelay(pdMS_TO_TICKS(1000));
            // 释放信号task_semphr
            xSemaphoreGive(task_semphr);
        }
    }
}

// 显屏任务
static void lcdTask(void* arg)
{
    while(true) {
        // 堵塞读取队列中的数据
        if(xSemaphoreTake(task_semphr, portMAX_DELAY)) {
            // 读取成功，刷新显屏（延时1s替代）
            ESP_LOGI(TAG, "take semaphore, display refresh for 1 second");
            // 延时1s
            vTaskDelay(pdMS_TO_TICKS(1000));            
        }
    }
}

void app_main(void)
{
    //button初始化
    button_init();

    //创建1个二值信号量
    isr_semphr = xSemaphoreCreateBinary();

    //创建1个二值信号量
    task_semphr = xSemaphoreCreateBinary();

    //创建1个任务，堆栈大小4096，优先级6
    xTaskCreate(coreTask, "coreTask", 4096, NULL, 6, NULL);

    //创建1个任务，堆栈大小4096，优先级5
    xTaskCreate(lcdTask, "lcdTask",  4096, NULL, 5,  NULL);
}